package com.zxl.always.on.display.tools;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Point;
import android.os.Build;
import android.os.Build.VERSION;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.ViewConfiguration;
import android.view.WindowManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 绘制工具类
 * @author luopeihuan
 *
 */
public class DrawUtils
{
	public static final PaintFlagsDrawFilter PAINTFLAG = new PaintFlagsDrawFilter(0,
			Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
	
	public static float sDensity = 1.0f;
	public static int sDensityDpi;
	public static int sWidthPixels;
	public static int sHeightPixels;
	public static float sFontDensity;
	public static int sTouchSlop = 15; // 点击的最大识别距离，超过即认为是移动

	public static int sStatusHeight; // 平板中底边的状态栏高度
	private static Class sClass = null;
	private static Method sMethodForWidth = null;
	private static Method sMethodForHeight = null;
	public static int sTopStatusHeight;
	
	public static int sNavBarLocation;
	private static int sRealWidthPixels;
	private static int sRealHeightPixels;
	private static int sNavBarWidth; // 虚拟键宽度
	private static int sNavBarHeight; // 虚拟键高度
	public static final int NAVBAR_LOCATION_RIGHT = 1;
	public static final int NAVBAR_LOCATION_BOTTOM = 2;

	// 在某些机子上存在不同的density值，所以增加两个虚拟值
	public static float sVirtualDensity = -1;
	public static float sVirtualDensityDpi = -1;

	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

	public static int px2dip(Context context, float pxValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (pxValue / scale + 0.5f);
	}

	public static int px2sp(float pxValue, float fontScale) {
		return (int) (pxValue / fontScale + 0.5f);
	}

	public static int sp2px(float spValue, float fontScale) {
		return (int) (spValue * fontScale + 0.5f);
	}

	/**
	 * dip/dp转像素
	 * 
	 * @param dipValue
	 *            dip或 dp大小
	 * @return 像素值
	 */
	public static int dip2px(float dipValue) {
		return (int) (dipValue * sDensity + 0.5f);
	}

	/**
	 * 像素转dip/dp
	 * 
	 * @param pxValue
	 *            像素大小
	 * @return dip值
	 */
	public static int px2dip(float pxValue) {
		final float scale = sDensity;
		return (int) (pxValue / scale + 0.5f);
	}

	/**
	 * sp 转 px
	 * 
	 * @param spValue
	 *            sp大小
	 * @return 像素值
	 */
	public static int sp2px(float spValue) {
		final float scale = sDensity;
		return (int) (scale * spValue);
	}

	/**
	 * px转sp
	 * 
	 * @param pxValue
	 *            像素大小
	 * @return sp值
	 */
	public static int px2sp(float pxValue) {
		final float scale = sDensity;
		return (int) (pxValue / scale);
	}

	public static void resetDensity(Context context) {
		if (context != null && null != context.getResources()) {
			DisplayMetrics metrics = context.getResources().getDisplayMetrics();
			sDensity = metrics.density;
			sFontDensity = metrics.scaledDensity;
			sWidthPixels = metrics.widthPixels;
			sHeightPixels = metrics.heightPixels;
			sDensityDpi = metrics.densityDpi;
			if (isPad()) {
				sStatusHeight = getTabletScreenHeight(context) - sHeightPixels;
			}
			try {
				final ViewConfiguration configuration = ViewConfiguration.get(context);
				if (null != configuration) {
					sTouchSlop = configuration.getScaledTouchSlop();
				}
				getStatusBarHeight(context);
			} catch (Error e) {
				Log.i("DrawUtils", "resetDensity has error" + e.getMessage());
			}
		}
		resetNavBarHeight(context);
	}

	private static void resetNavBarHeight(Context context) {
		if (context != null) {
			WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
			Display display = wm.getDefaultDisplay();
			try {
				if (sClass == null) {
					sClass = Class.forName("android.view.Display");
				}
				Point realSize = new Point();
				Method method = sClass.getMethod("getRealSize", Point.class);
				method.invoke(display, realSize);
				sRealWidthPixels = realSize.x;
				sRealHeightPixels = realSize.y;
				sNavBarWidth = realSize.x - sWidthPixels;
				sNavBarHeight = realSize.y - sHeightPixels;
			} catch (Exception e) {
				sRealWidthPixels = sWidthPixels;
				sRealHeightPixels = sHeightPixels;
				sNavBarHeight = 0;
			}
		}
		sNavBarLocation = getNavBarLocation();
	}

	public static int getTabletScreenWidth(Context context) {
		int width = 0;
		if (context != null) {
			try {
				WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
				Display display = wm.getDefaultDisplay();
				if (sClass == null) {
					sClass = Class.forName("android.view.Display");
				}
				if (sMethodForWidth == null) {
					sMethodForWidth = sClass.getMethod("getRealWidth");
				}
				width = (Integer) sMethodForWidth.invoke(display);
			} catch (Exception e) {
			}
		}

		// Rect rect= new Rect();
		// ((Activity)
		// context).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
		// int statusbarHeight = height - rect.bottom;
		if (width == 0) {
			width = sWidthPixels;
		}

		return width;
	}

	public static int getTabletScreenHeight(Context context) {
		int height = 0;
		if (context != null) {
			WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
			Display display = wm.getDefaultDisplay();
			try {
				if (sClass == null) {
					sClass = Class.forName("android.view.Display");
				}
				if (sMethodForHeight == null) {
					sMethodForHeight = sClass.getMethod("getRealHeight");
				}
				height = (Integer) sMethodForHeight.invoke(display);
			} catch (Exception e) {
			}
		}

		// Rect rect= new Rect();
		// ((Activity)
		// context).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
		// int statusbarHeight = height - rect.bottom;
		if (height == 0) {
			height = sHeightPixels;
		}

		return height;
	}
	
	public static boolean isPad() {
		if (sDensity >= 1.5 || sDensity <= 0) {
			return false;
		}
		if (sWidthPixels < sHeightPixels) {
			if (sWidthPixels > 480 && sHeightPixels > 800) {
				return true;
			}
		} else {
			if (sWidthPixels > 800 && sHeightPixels > 480) {
				return true;
			}
		}
		return false;
	}
	
	public static int getStatusBarHeight(Context context)
	{
		Class<?> c = null;
		Object obj = null;
		Field field = null;
		int x = 0;
		int top = 0;
		try
		{
			c = Class.forName("com.android.internal.R$dimen");
			obj = c.newInstance();
			field = c.getField("status_bar_height");
			x = Integer.parseInt(field.get(obj).toString());
			top = context.getResources().getDimensionPixelSize(x);
			sTopStatusHeight = top;
		}
		catch (Exception e1)
		{
			e1.printStackTrace();
		}
		return top;
	}
	
	public static Bitmap getGaussinaBlur(Context context, Bitmap sentBitmap, int radius) {
		try {
			return getGaussina(context, sentBitmap, radius);
		} catch (OutOfMemoryError oom) {
			 
			System.gc();
		} catch (Exception e) {
			 
		}
		return sentBitmap;

	}

	@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
	public static Bitmap getGaussina(Context context, Bitmap sentBitmap, int radius) {
		Bitmap bitmap = null;
		try {
			if (VERSION.SDK_INT >= 17) {
				if (radius > 25) {
					radius = 25;
				}
				bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);

				RenderScript rs = RenderScript.create(context);
				Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE,
						Allocation.USAGE_SCRIPT);
				Allocation output = Allocation.createTyped(rs, input.getType());
				ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
				script.setRadius(radius /* e.g. 3.f */);
				script.setInput(input);
				script.forEach(output);
				output.copyTo(bitmap);
				if (rs != null) {
					rs.finish();
					rs.destroy();
					rs = null;
				}
				if (input != null) {
					input.destroy();
					input = null;
				}
				if (output != null) {
					output.destroy();
					output = null;
				}
				if (script != null) {
					script.destroy();
					script = null;
				}
				return bitmap;
			}
			bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
			
			if (radius < 1) {
				return null;
			}
			
			int w = bitmap.getWidth();
			int h = bitmap.getHeight();
			
			int[] pix = new int[w * h];
			bitmap.getPixels(pix, 0, w, 0, 0, w, h);
			
			int wm = w - 1;
			int hm = h - 1;
			int wh = w * h;
			int div = radius + radius + 1;
			
			int r[] = new int[wh];
			int g[] = new int[wh];
			int b[] = new int[wh];
			int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
			
			int vmin[] = new int[Math.max(w, h)];
			
			int divsum = (div + 1) >> 1;
			divsum *= divsum;
			int dv[] = new int[256 * divsum];
			for (i = 0; i < 256 * divsum; i++) {
				dv[i] = i / divsum;
			}
			
			yw = yi = 0;
			
			int[][] stack = new int[div][3];
			int stackpointer;
			int stackstart;
			int[] sir;
			int rbs;
			int r1 = radius + 1;
			int routsum, goutsum, boutsum;
			int rinsum, ginsum, binsum;
			
			for (y = 0; y < h; y++) {
				rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
				for (i = -radius; i <= radius; i++) {
					p = pix[yi + Math.min(wm, Math.max(i, 0))];
					sir = stack[i + radius];
					sir[0] = (p & 0xff0000) >> 16;
				sir[1] = (p & 0x00ff00) >> 8;
			sir[2] = p & 0x0000ff;
			rbs = r1 - Math.abs(i);
			rsum += sir[0] * rbs;
			gsum += sir[1] * rbs;
			bsum += sir[2] * rbs;
			if (i > 0) {
				rinsum += sir[0];
				ginsum += sir[1];
				binsum += sir[2];
			} else {
				routsum += sir[0];
				goutsum += sir[1];
				boutsum += sir[2];
			}
				}
				stackpointer = radius;
				
				for (x = 0; x < w; x++) {
					
					r[yi] = dv[rsum];
					g[yi] = dv[gsum];
					b[yi] = dv[bsum];
					
					rsum -= routsum;
					gsum -= goutsum;
					bsum -= boutsum;
					
					stackstart = stackpointer - radius + div;
					sir = stack[stackstart % div];
					
					routsum -= sir[0];
					goutsum -= sir[1];
					boutsum -= sir[2];
					
					if (y == 0) {
						vmin[x] = Math.min(x + radius + 1, wm);
					}
					p = pix[yw + vmin[x]];
					
					sir[0] = (p & 0xff0000) >> 16;
				sir[1] = (p & 0x00ff00) >> 8;
				sir[2] = p & 0x0000ff;
				
				rinsum += sir[0];
				ginsum += sir[1];
				binsum += sir[2];
				
				rsum += rinsum;
				gsum += ginsum;
				bsum += binsum;
				
				stackpointer = (stackpointer + 1) % div;
				sir = stack[stackpointer % div];
				
				routsum += sir[0];
				goutsum += sir[1];
				boutsum += sir[2];
				
				rinsum -= sir[0];
				ginsum -= sir[1];
				binsum -= sir[2];
				
				yi++;
				}
				yw += w;
			}
			for (x = 0; x < w; x++) {
				rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
				yp = -radius * w;
				for (i = -radius; i <= radius; i++) {
					yi = Math.max(0, yp) + x;
					
					sir = stack[i + radius];
					
					sir[0] = r[yi];
					sir[1] = g[yi];
					sir[2] = b[yi];
					
					rbs = r1 - Math.abs(i);
					
					rsum += r[yi] * rbs;
					gsum += g[yi] * rbs;
					bsum += b[yi] * rbs;
					
					if (i > 0) {
						rinsum += sir[0];
						ginsum += sir[1];
						binsum += sir[2];
					} else {
						routsum += sir[0];
						goutsum += sir[1];
						boutsum += sir[2];
					}
					
					if (i < hm) {
						yp += w;
					}
				}
				yi = x;
				stackpointer = radius;
				for (y = 0; y < h; y++) {
					// Preserve alpha channel: ( 0xff000000 & pix[yi] )
					pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
							| (dv[gsum] << 8) | dv[bsum];
					
					rsum -= routsum;
					gsum -= goutsum;
					bsum -= boutsum;
					
					stackstart = stackpointer - radius + div;
					sir = stack[stackstart % div];
					
					routsum -= sir[0];
					goutsum -= sir[1];
					boutsum -= sir[2];
					
					if (x == 0) {
						vmin[y] = Math.min(y + r1, hm) * w;
					}
					p = x + vmin[y];
					
					sir[0] = r[p];
					sir[1] = g[p];
					sir[2] = b[p];
					
					rinsum += sir[0];
					ginsum += sir[1];
					binsum += sir[2];
					
					rsum += rinsum;
					gsum += ginsum;
					bsum += binsum;
					
					stackpointer = (stackpointer + 1) % div;
					sir = stack[stackpointer];
					
					routsum += sir[0];
					goutsum += sir[1];
					boutsum += sir[2];
					
					rinsum -= sir[0];
					ginsum -= sir[1];
					binsum -= sir[2];
					
					yi += w;
				}
			}
			bitmap.setPixels(pix, 0, w, 0, 0, w, h);
			pix = null;
		} catch (OutOfMemoryError e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
		return bitmap;
	}
	
	public static int getRealWidth() {
		if (MachineUtils.HAS_SDK_KITKAT) {
			return sRealWidthPixels;
		}
		return sWidthPixels;
	}
	
	public static int getRealHeight() {
		if (MachineUtils.HAS_SDK_KITKAT) {
			return sRealHeightPixels;
		}
		return sHeightPixels;
	}
	

	/**
	 * 虚拟键在下面时
	 * @return
	 */
	public static int getNavBarHeight() {
		if (MachineUtils.HAS_SDK_KITKAT) {
			return sNavBarHeight;
		}
		return 0;
	}
	
	/**
	 * 横屏，虚拟键在右边时
	 * @return
	 */
	public static int getNavBarWidth() {
		if (MachineUtils.HAS_SDK_KITKAT) {
			return sNavBarWidth;
		}
		return 0;
	}
	
	public static int getNavBarLocation() {
		if (sRealWidthPixels > sWidthPixels) {
			return NAVBAR_LOCATION_RIGHT;
		}
		return NAVBAR_LOCATION_BOTTOM;
	}
	
	/**
	 * 判断锁屏是否竖屏
	 * @param context
	 * @return
	 */
	public static boolean isScreenPortrait(Context context) {
		DisplayMetrics display = context.getResources().getDisplayMetrics();
		int h = display.heightPixels;
		int w = display.widthPixels;
		if (h > w) {
			return true;
		}
		return false;
	}

	public static int getScreenWidth() {
		return sWidthPixels;
	}

	public static int getScreenHeight() {
		return sHeightPixels;
	}

	public static int dip2pxForXH(float dipValue) {
		return (int) (dipValue / 2 * sDensity + 0.5f);
	}
}
